package com.github.xzb617.adm.service.impl;

import com.github.xzb617.adm.dao.RouteRuleMapper;
import com.github.xzb617.adm.service.RouteRuleItemService;
import com.github.xzb617.adm.service.RouteRuleService;
import com.github.xzb617.client.config.ClientsTransmitter;
import com.github.xzb617.client.config.key.ClientKeyType;
import com.github.xzb617.client.route.props.RuleProperties;
import com.github.xzb617.domain.common.PageTextCondition;
import com.github.xzb617.domain.dto.RouteDTO;
import com.github.xzb617.domain.entity.RouteRule;
import com.github.xzb617.domain.entity.RouteRuleItem;
import com.github.xzb617.utils.MapKeyFormatUtil;
import com.github.xzb617.utils.ObjectMapUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.*;

@Service
public class RouteRuleServiceImpl implements RouteRuleService {

    private final RouteRuleMapper routeRuleMapper;
    private final RouteRuleItemService routeRuleItemService;
    private final ClientsTransmitter clientsTransmitter;

    public RouteRuleServiceImpl(RouteRuleMapper routeRuleMapper, RouteRuleItemService routeRuleItemService, ClientsTransmitter clientsTransmitter) {
        this.routeRuleMapper = routeRuleMapper;
        this.routeRuleItemService = routeRuleItemService;
        this.clientsTransmitter = clientsTransmitter;
    }

    @Override
    public Map<String, Object> getClientFlowConfig(String routeRuleName) {
        // 查询 RouteRule
        Example example = new Example(RouteRule.class);
        example.createCriteria().andEqualTo("routeRuleName", routeRuleName);
        RouteRule routeRule = this.routeRuleMapper.selectOneByExample(example);
        if (routeRule == null) {
            return null;
        }

        // 查询 RouteRuleItem
        List<RouteRuleItem> items = this.routeRuleItemService.getListByRouteRuleId(routeRule.getId());

        // 数据转换
        RuleProperties ruleProp = new RuleProperties();
        Map<String, Map<String, com.github.xzb617.client.route.dto.RouteRule>> rules = ruleProp.getRules();
        Map<String, com.github.xzb617.client.route.dto.RouteRule> ipRuleMap     = new HashMap<>();
        Map<String, com.github.xzb617.client.route.dto.RouteRule> headerRuleMap = new HashMap<>();
        Map<String, com.github.xzb617.client.route.dto.RouteRule> queryRuleMap  = new HashMap<>();
        for (RouteRuleItem item : items) {
            String ruleType = item.getRuleType();
            if ("IP".equals(ruleType)) {
                // ip含有 '.'
                String ruleKey = MapKeyFormatUtil.escape(item.getRuleKey());
                ipRuleMap.put(ruleKey, convertToRouteRule(item));
            }
            if ("HEADER".equals(ruleType)) {
                String ruleKey = MapKeyFormatUtil.escape(item.getRuleKey());
                headerRuleMap.put(ruleKey, convertToRouteRule(item));
            }
            if ("QUERY".equals(ruleType)) {
                String ruleKey = MapKeyFormatUtil.escape(item.getRuleKey());
                queryRuleMap.put(ruleKey, convertToRouteRule(item));
            }
        }
        rules.put("IP", ipRuleMap);
        rules.put("HEADER", headerRuleMap);
        rules.put("QUERY", queryRuleMap);

        return ObjectMapUtil.objToMap("goalkeeper.route.rule", ruleProp);
    }


    private com.github.xzb617.client.route.dto.RouteRule convertToRouteRule(RouteRuleItem item) {
        com.github.xzb617.client.route.dto.RouteRule rule = new com.github.xzb617.client.route.dto.RouteRule();
        rule.setCallerAppId(item.getCallerAppId());
        rule.setCallerKey(item.getCallerKey());
        rule.setCallerValue(item.getCallerValue());
        rule.setCalleeAppId(item.getCalleeAppId());
        // 此处暂且固定用 gk-route-rule
        rule.setCalleeLabel(item.getCalleeLabel());
        rule.setCalleeLabelValue(item.getCalleeLabelValue());
        rule.setWeight(item.getWeight());
        return rule;
    }

    @Override
    public RouteRule getById(Integer id) {
        return this.routeRuleMapper.selectByPrimaryKey(id);
    }

    @Override
    public RouteRule getByName(String routeName) {
        Example example = new Example(RouteRule.class);
        example.createCriteria().andEqualTo("routeRuleName", routeName)
                .andEqualTo("status", true);
        return this.routeRuleMapper.selectOneByExample(example);
    }

    @Override
    public List<RouteRule> getList(PageTextCondition condition) {
        Example example = new Example(RouteRule.class);
        Example.Criteria criteria = example.createCriteria();
        if (condition.isNotEmptyOrNull()) {
            criteria.andLike("routeRuleName", condition.like())
                    .orLike("remark", condition.like());
        }
        return this.routeRuleMapper.selectByExample(example);
    }

    @Override
    @Transactional
    public void update(RouteDTO dto) {
        // 更新 RouteRule
        RouteRule routeRule = dto.getRouteRule();
        routeRule.setUpdateTime(new Date());
        routeRule.setSign(UUID.randomUUID().toString());
        this.routeRuleMapper.updateByPrimaryKeySelective(routeRule);
        // 更新 RouteRuleItem
        this.routeRuleItemService.update(routeRule.getId(), dto.getRouteRuleItems());
        // 下发通知客户端路由配置更新
        this.clientsTransmitter.transmitClient(ClientKeyType.ROUTE, routeRule.getRouteRuleName());
    }

}
